raf-schd
A scheduler based on requestAnimationFrame
. It throttles calls to a function and only invokes it with the latest argument in the frame period.

import rafSchedule from 'raf-schd';
const expensiveFn = (arg) => {
console.log(arg);
}
const schedule = rafSchedule(expensiveFn);
schedule('foo');
schedule('bar');
schedule('baz');
Why?
raf-schd
supports the use case where you only want to perform an action in an animation frame with the latest value. This an extremely useful performance optmisation.
Without raf-schd
Optimised scroll listener example taken from MDN
var last_known_scroll_position = 0;
var ticking = false;
function doSomething(scroll_pos) {
}
window.addEventListener('scroll', function(e) {
last_known_scroll_position = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(function() {
doSomething(last_known_scroll_position);
ticking = false;
});
}
ticking = true;
});
With raf-schd
import rafSchedule from 'raf-schd';
function doSomething(scroll_pos) {
}
const schedule = rafSchedule(doSomething);
window.addEventListener('scroll', function() {
schedule(window.scrollY);
});
Types
rafSchduler
type rafSchedule = (fn: Function) => ResultFn
type WrapperFn = (...arg: any[]) => number;
type CancelFn = {|
cancel: () => void,
|};
type ResultFn = WrapperFn & CancelFn;
At the top level raf-schd
accepts any function a returns a new ResultFn
(a function that wraps your original function). When executed, the ResultFn
returns a number
. This number is the animation frame id. You can cancel a frame using the .cancel()
property on the ResultFn
.
The ResultFn
will execute your function with the latest arguments provided to it on the next animation frame.
Throttled with latest argument
import rafSchedule from 'raf-schd';
const doSomething = () => {...};
const schedule = rafSchedule(doSomething);
schedule(1, 2);
schedule(3, 4);
schedule(5, 6);
Cancelling a frame
.cancel
raf-schd
adds a .cancel
property to the ResultFn
so that it can be easily cancelled. The frame will only be cancelled if it has not yet executed.
const scheduled = rafSchedule(doSomething);
schedule('foo');
scheduled.cancel();
cancelAnimationFrame
You can use cancelAnimationFrame
directly to cancel a frame if you like. You can do this because you have the frameId
.
const scheduled = rafSchedule(doSomething);
const frameId = schedule('foo');
cancelAnimationFrame(frameId);
Is this a throttle
, debounce
or something else?
raf-schd
is closer to throttle
than it is debounce
. It is not like debounce
because it does not wait for a period of quiet before firing the function.
Lets take a look at the characteristics of this library:
Similarities to throttle
- It batches multiple calls into a single event
- It only executes the wrapped function with the latest argument
- It will not execute anything if the function is not invoked
- One invokation of a scheduled function always results in at least one function call, unless canceled. This is
throttle
with tail calls enabled.
Differences to throttle
- Rather than throttling based on time (such as
200ms
, this library throttles based on requestAnimationFrame
. This allows the browser to control how many frames to provide per second to optimise rendering. - Individual frames of
raf-schd
can be canceled using cancelAnimationFrame
as it returns the frame id.
Testing your code
If you want to really ensure that your code is working how you intend it to - use raf-stub
to test your animation frame logic.
Installation
yarn add raf-schd
npm install raf-schd --save
Module usage
ES6 module
import rafSchedule from 'raf-schd';
CommonJS
If you are in a CommonJS environment (eg Node), then you will need add .default
to your import:
const rafSchedule = require('raf-schd').default;